package com.develop.collection.middle.sensors;

import com.develop.collection.util.Entry;
import com.develop.jdbc.jdbc.DataRow;
import com.develop.jdbc.jdbc.session.Session;
import com.develop.jdbc.jdbc.session.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 评分计算
 *
 * @author fenny
 * @since 2019/08/19
 */
public class ScoreCalculation {

    private static final Logger log = LoggerFactory.getLogger(ScoreCalculation.class);

    private static final AtomicInteger SUCCESS_COUNT = new AtomicInteger();

    private static final AtomicInteger FILTER_COUNT = new AtomicInteger();

    private static final AtomicInteger CONVERT_COUNT = new AtomicInteger();

    /**
     * 事件_用户_产品_
     * 获取所有用户
     * 计算每个用户对应产品的评分
     * 写入txt
     */
    private static void execute() {
        log.info("begin-计算");
        int currTotal = 0;
        long beginTime;
        ExecutorService pool = Executors.newFixedThreadPool(10000);
        String fileName = "recommendations.txt";
        try {
            Session mysql = SessionFactory.getSession("local-mysql");
            beginTime = System.currentTimeMillis();
            List<DataRow> result = mysql.query(String.format("select user_id from user"));
            log.info("加载用户耗时={}ms", System.currentTimeMillis() - beginTime);
            mysql.close();
            if (result.size() > 0) {
                CountDownLatch latch = new CountDownLatch(result.size());
                currTotal += result.size();
                for (DataRow row : result) {
                    pool.submit(() -> {
                        Session newMysql = null;
                        try {
                            long userId = row.getLong("user_id");
                            newMysql = SessionFactory.getSession("local-mysql");
                            List<DataRow> calResult = newMysql.query("select user_id,sku_id,(ifnull((select num * 0.4 from summary where event='addToShoppingcart' and user_id = a.user_id and sku_id=a.sku_id),0)\n" +
                                    "+ifnull((select num * 0.2 from summary where event='submitOrderDetail' and user_id = a.user_id and sku_id=a.sku_id),0)\n" +
                                    "+ifnull((select num * 0.4 from summary where event='payOrderDetail' and user_id = a.user_id and sku_id=a.sku_id),0)) as score\n" +
                                    String.format("from summary a where user_id = %s and event in ('addToShoppingcart','submitOrderDetail','payOrderDetail') group by user_id,sku_id", userId));
                            for (DataRow calRow : calResult) {
                                append(fileName, String.format("%d,%d,%.4f", calRow.getLong("user_id"), calRow.getLong("sku_id"), calRow.getFloat("score")));
                                SUCCESS_COUNT.incrementAndGet();
                            }
                        } catch (Exception e) {
                            log.error("", e);
                        } finally {
                            latch.countDown();
                            if (newMysql != null) {
                                newMysql.close();
                            }
                        }
                    });
                }
                latch.await();
            }
            log.info("总耗时{}秒,写入={}", ((System.currentTimeMillis() - beginTime) / 1000), SUCCESS_COUNT.get());
        } catch (Exception e) {
            log.error("", e);
        } finally {
            pool.shutdown();
            log.info("原数据量={},过滤量={},写入量={},转换量={}", currTotal, FILTER_COUNT.get(), SUCCESS_COUNT.get(), CONVERT_COUNT.get());
            log.info("end-计算");
        }
    }

    public static void main(String[] args) {
        Entry.entry(ScoreCalculation::execute);
    }

    private static void append(String fileName, String content) {
        FileWriter writer = null;
        try {
            // 打开一个写文件器，构造函数中的第二个参数true表示以追加形式写文件
            writer = new FileWriter(fileName, true);
            writer.write(content);
            writer.write("\n");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
